#include "eedit_mem.h"
#include "eedit_syntax.h"

file_buffer_t newBuffer(){
    file_buffer_t* localBuffer = (file_buffer_t*)calloc(1,sizeof(file_buffer_t));
    localBuffer->head=newLine();
    localBuffer->tail=local_buffer->head;
    localBuffer->length = 1;
    localBuffer->cursorLine=1;
    localBuffer->cursorCol=1;
    localBuffer->prev_cursorLine=0;
    localBuffer->prev_position=0;

    return localBuffer;
}

void priv_line_shift_right(line_t* l){
    int i=l->length-1;
    for( ; i >= 0; i--){
        l->mem[i+1] = l->mem[i];
    }
    l->length++;
    l->displayLength++;
}

void delBuffer(file_buffer_t* fb_t){
    int i;
    /* Remove Lines */
    line_t* cursor = fb_t->head;

    if(cursor==NULL){
        free(fb_t);
        return;
    }

    for(i=1;i<=fb_t->length;i++){
        if(fb_t->next==NULL&&i!=length-1)
            DEBUG_FATAL("Broken list, NULL found whilst count remains");

        delBufferLine(fb_t,i);
    }
    
}

/* Is this needed */
void addNewLine(file_buffer_t* fb_t){}

/* TODO: Modify to take the shortest path */
void delBufferLine(file_buffer_t* fb_t,int line){
    line_t* cursor;
    line_t* prev;
    line_t* next;
    cursor = getBufferLine(fb_t,line);
    assert(cursor!=NULL);
    if(cursor->syn!=NULL){
        delSyntax(cursor->syn);
    }
    
    prev = cursor->prev;
    next = cursor->next;

    if(prev!=NULL)
    prev->next=next;
    
    if(next!=NULL)
    next->prev=prev;

    free(cursor->mem);
    free(cursor);

    fb_t->length--;
    
    /* reset prev_ markers */
    fb_t->prev_cursorLine=0;
    fb_t->prev_position=0;
}


/* TODO: Modify to take the shortest path */
line_t* getBufferLine(file_buffer_t* fb_t,int line){
    line_t* cursor;
    int i;
    assert(fb_t->length>=line);
    assert(fb_t->head!=NULL);
    cursor=fb_t->head;
    /* FIXME: off by one? */
    for(i=1;i<line;i++){
        if(cursor->next==NULL)
            DEBUG_FATAL("line list too short");
        cursor=cursor->next;
    }
    return cursor;
}

/* TODO: Contextual Seeking */
void addBufferChar(file_buffer_t* fb_t, CHARACTER c, POSITION p){
    line_t* cursor;
    line_t* newLine;
    POSITION cp = 0;
    int i;
    assert(fb_t->length>0);
    assert(fb_t->head!=NULL);
    cursor=fb_t->head;

    /* Find the correct line */ 
    for(i=1;i<fb_t->length;i++){
        cp+=(POSITION)cursor->display_len;
        if(cp>=p)
            break;
        cursor=cursor->next;
    }

    /* Ok, so we know we are on a line that includes the target position */

    /* The position is the last character */
    if(cp==p){
        /* Check there is a next line */
        if(END_CHECK(cursor)){
            /* Create new line */
            newLine = (line_t)calloc(1,sizeof(line_t));
            cursor->next = newLine;
            newLine->prev = cursor;
            fb_t->tail = newLine;
            fb_t->length++;
            /* Copy the last char from the previous line to the first char of this new line */
            newLine->mem[0] = cursor->mem[LINE_SIZE-1];
            newLine->length = 1;
            newLine->display_length = 1;
            cursor->mem[LINE_SIZE-1] = c;
        }
        /* See if the next line can accomodate the moved character */
        if(cursor->next->length==LINE_SIZE){    //NO SPACE
            /*Create a middle linked line*/
            newLine = (line_t)calloc(1,sizeof(line_t));
            newLine->next = cursor->next;
            newLine->prev = cursor;
            cursor->next = newLine;
            fb_t->length++;
            newLine->mem[0] = cursor->mem[LINE_SIZE-1];
            newLine->length = 1;
            newLine->display_length = 1;
            cursor->mem[LINE_SIZE-1] = c;
        }else{                                  //HAS SPACE
            priv_line_shift_right(cursor->next);
            cursor->next->mem[0] = cursor->mem[LINE_SIZE-1];
            cursor->mem[LINE_SIZE-1]=c;
            /* Lengths remain the same */
        }
    }
    /* Position was not the last character. Simply add a character and move on */

}

/* Called when text is pasted, I guess */
void addBufferStr(file_buffer_t* fb_t, char * string, POSITION p){
    int len;
    int req;
    int line_pos = 0;
    int line_count = 0;
    char * ptr;
    line_t *local;
    line_t *temp;
    line_t *head;
    line_t *tail;
    line_t *insert_after;

    len = strlen(string);

    /* Create a local linked list and then
     * insert into the correct position in the buffer
     */
    local = (line_t*)calloc(1,sizeof(line_t));
    local->next = NULL;
    local->temp = NULL;
    head = local;
    line_count++;
    line_pos = 0;


    /* Copy the first char arbitarily. This allows us to avoid
     * dividing by zero in the for loop 
     */
    /*
     * FIXME: Replace with memcpy
     */
    for(i=0;i<len;i++){
        if(line_pos==LINE_SIZE){
            temp = (line_t*)calloc(1,sizeof(line_t));
            temp->prev = local;
            local->next = prev;
            tail->temp;
            local=temp;
            line_count++;
            line_pos=0;
        }
        local->mem[line_pos] = string[i];
        line_pos++;
    }

    insert_after = getBufferLine(fb_t,(position/LINE_SIZE)); //+1 ?
    head->prev=insert_after;
    tail->next=inset_after->next;
    insert_after->next=head;
}

void createFold(POSITION){}

void unfold(POSITION){}
